﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Composition;
using ScrumFactory.Composition;
using ScrumFactory.Composition.ViewModel;
using ScrumFactory.Backlog.ViewModel;
using ScrumFactory.Tasks.ViewModel;
using System.Windows.Input;
using System.Collections.ObjectModel;


namespace ScrumFactory.HelpDeskPlugin.ViewModels {

    [Export]
    [Export(typeof(IDockPanelViewModel))]
    public class HelpDeskViewModel : BasePanelViewModel, IDockPanelViewModel, INotifyPropertyChanged {

        [Import]
        private Services.IProjectsService projectsService { get; set; }
        
        [Import]
        private Services.IBacklogService backlogService { get; set; }

        [Import]
        private Services.ITasksService taskService { get; set; }

        [Import]
        private Services.IAuthorizationService authorizator { get; set; }
                
        [Import]
        private IBackgroundExecutor executor { get; set; }

        private ScrumFactory.Composition.IEventAggregator aggregator;

        private ICollection<Project> projects;
        public ICollection<Project> Projects {
            get {
                return projects;
            }
            set {
                projects = value;
                OnPropertyChanged("Projects");
            }
        }

        private Project newTicketProject;
        public Project NewTicketProject {
            get {
                return newTicketProject;
            }
            set {
                newTicketProject = value;
                OnPropertyChanged("NewTicketProject");
            }
        }

        private string newTicketName;
        public string NewTicketName {
            get {
                return newTicketName;
            }
            set {
                newTicketName = value;
                OnPropertyChanged("NewTicketName");
            }
        }


        private Project CurrentProject { get; set; }

        private string newTaskName;
        public string NewTaskName {
            get {
                return newTaskName;
            }
            set {
                newTaskName = value;
                OnPropertyChanged("NewTaskName");
            }
        }
        
        public bool IsFocusAtNewTask {
            get {
                return isAddingTask;
            }            
        }

        private bool isAddingTask;
        public bool IsAddingTask {
            get {
                return isAddingTask;
            }
            set {
                isAddingTask = value;
                OnPropertyChanged("IsAddingTask");
                OnPropertyChanged("IsFocusAtNewTask");
            }
        }

    
        private ICollection<Task> tasks;
        public ICollection<Task> Tasks {
            get {
                return tasks;
            }
            set {
                tasks = value;
                OnPropertyChanged("Tasks");
            }
        }

        public bool CanAddTask() {
            if (SelectedItem == null || SelectedItem.Item == null || SelectedItem.Item.Project == null || SelectedItem.Item.Project.Roles == null)
                return false;

            return SelectedItem.Item.Project.Memberships.Any(m => m.MemberUId == authorizator.SignedMemberProfile.MemberUId);
        }

        public bool CanCloseJob() {
            if (SelectedItem == null || SelectedItem.Item == null || SelectedItem.Item.Project == null || SelectedItem.Item.Project.Roles == null)
                return false;

            if (!SelectedItem.Item.Project.HasPermission(authorizator.SignedMemberProfile.MemberUId, PermissionSets.SCRUM_MASTER))
                return false;

            return (SelectedItem.Item.Status == (short)BacklogItemStatus.ITEM_REQUIRED || SelectedItem.Item.Status == (short)BacklogItemStatus.ITEM_WORKING);
        }

        private void CloseJob() {

            if (SelectedItem == null || SelectedItem.Item == null)
                return;

            executor.StartBackgroundTask(() => {
                backlogService.ChangeBacklogItemStatus(SelectedItem.Item.BacklogItemUId, (short)BacklogItemStatus.ITEM_DONE);
            },
            () => { 
                SelectedItem.ItemStatus = (short)BacklogItemStatus.ITEM_DONE;
                ((ScrumFactory.Composition.DelegateCommand)CloseJobCommand).NotifyCanExecuteChanged();
            });
        }


        private void AddTask() {
            IsAddingTask = true;
            NewTaskName = "";
        }

        private void ConfirmAddTask() {

            Task task = new Task();
            task.TaskUId = Guid.NewGuid().ToString();
            task.Status = (short)TaskStatus.REQUIRED_TASK;
            task.PlannedHours = 0.0M;
            task.EffectiveHours = 0.0M;
            task.TaskName = NewTaskName;
            task.TaskType = 1;
            task.ProjectUId = SelectedItem.Item.ProjectUId;
            task.BacklogItemUId = SelectedItem.Item.BacklogItemUId;
            task.TaskOwnerUId = authorizator.SignedMemberProfile.MemberUId;
            task.TaskAssigneeUId = authorizator.SignedMemberProfile.MemberUId;
            task.CreatedAt = DateTime.Now;
            task.IsAccounting = true;

            executor.StartBackgroundTask<int>(() => {
                return taskService.CreateTask(task);
            },
            taskNumber => {
                task.TaskNumber = taskNumber;
                Tasks.Add(task);
                IsAddingTask = false;
            });
        }

        private void CancelAddTask() {            
            IsAddingTask = false;
        }


        private void ShowTask(Task task) {
            aggregator.Publish<Task>(ScrumFactoryEvent.ShowTaskDetail, task);
        }

        private void ShowItem() {
            if (SelectedItem == null || SelectedItem.Item==null)
                return;
            aggregator.Publish<BacklogItem>(ScrumFactoryEvent.ShowItemDetail, SelectedItem.Item);
        }

        private BacklogItemViewModel selectedItem { get; set; }
        public BacklogItemViewModel SelectedItem {
            get {
                return selectedItem;
            }
            set {
                
                selectedItem = value;

                LoadTasks();
                
                bool projectChanged = (selectedItem == null || selectedItem.Item == null || CurrentProject==null || CurrentProject.ProjectUId != selectedItem.Item.ProjectUId);
                if(projectChanged)
                    LoadProjectRoles();
                else
                    selectedItem.Item.Project = CurrentProject;
                    
                OnPropertyChanged("SelectedItem");
                IsAddingTask = false;                
            }
        }

        private bool onlyMineProjects = true;
        public bool OnlyMineProjects {
            get {
                return onlyMineProjects;
            }
            set {
                onlyMineProjects = value;
                OnPropertyChanged("OnlyMineProjects");
                LoadData();
            }
        }


        [ImportingConstructor]
        public HelpDeskViewModel([Import] ScrumFactory.Composition.IEventAggregator aggregator) {

            this.aggregator = aggregator;

            OnLoadCommand = new ScrumFactory.Composition.DelegateCommand(() => { if (NeedRefresh) LoadData(); });

            RefreshCommand = new ScrumFactory.Composition.DelegateCommand(LoadData);

            ShowTaskCommand = new ScrumFactory.Composition.DelegateCommand<Task>(ShowTask);
            ShowItemCommand = new ScrumFactory.Composition.DelegateCommand(ShowItem);
            CloseJobCommand = new ScrumFactory.Composition.DelegateCommand(CanCloseJob, CloseJob);
            
            AddTaskCommand = new ScrumFactory.Composition.DelegateCommand(CanAddTask, AddTask);
            ConfirmAddTaskCommand = new ScrumFactory.Composition.DelegateCommand(ConfirmAddTask);
            CancelAddTaskCommand = new ScrumFactory.Composition.DelegateCommand(CancelAddTask);

            NeedRefresh = true;
        }

        private void LoadData() {            
            LoadProjects(LoadBacklogItems);
            NeedRefresh = false;
        }

        private void LoadBacklogItems() {
            
            executor.StartBackgroundTask<ICollection<BacklogItem>>(() => {
                return backlogService.GetAllUnfinishedBacklogItems(OnlyMineProjects);
            },
            items => {
                List<BacklogItemViewModel> vms = new List<BacklogItemViewModel>();
                foreach (BacklogItem i in items.OrderByDescending(i => i.IssueType).ThenBy(i => i.CreateDate).ThenBy(i => i.BusinessPriority)) {
                    Project project = projects.SingleOrDefault(p => p.ProjectUId == i.ProjectUId);
                    vms.Add(new BacklogItemViewModel(backlogService, executor, aggregator, authorizator, project, i));
                }
                BacklogItems = vms;
                IsLoadingData = false;
            });
        }

        private void LoadProjects(Action after) {
            IsLoadingData = true;
            executor.StartBackgroundTask<ICollection<Project>>(() => {
                return projectsService.GetProjects(null, null, "RUNNING_PROJECTS", authorizator.SignedMemberProfile.MemberUId);
            },
            prjs => {
                Projects = prjs;
                after.Invoke();
            });
        }

        private void LoadProjectRoles() {

            if (SelectedItem == null || SelectedItem.Item == null)
                return;

            SelectedItem.Item.Project.Roles = null;
            SelectedItem.Item.Project.Memberships = null;

            ((ScrumFactory.Composition.DelegateCommand)CloseJobCommand).NotifyCanExecuteChanged();  
            ((ScrumFactory.Composition.DelegateCommand)AddTaskCommand).NotifyCanExecuteChanged();  


            // loads the full project with roles and assign to item
            executor.StartBackgroundTask<Project>(() => {
                return projectsService.GetProject(SelectedItem.Item.ProjectUId);
            },
            project => {
                CurrentProject = project;
                SelectedItem.Item.Project = project;
                SelectedItem.Item.SyncPlannedHoursAndRoles();
                ((ScrumFactory.Composition.DelegateCommand)CloseJobCommand).NotifyCanExecuteChanged();
                ((ScrumFactory.Composition.DelegateCommand)AddTaskCommand).NotifyCanExecuteChanged(); 
            });
        }

        private void LoadTasks() {
            if (SelectedItem == null) {
                Tasks = new ObservableCollection<Task>();
                return;
            }

            executor.StartBackgroundTask<ICollection<Task>>(() => {
                return taskService.GetItemTasks(SelectedItem.Item.BacklogItemUId);
            },
            tasks => {
                Tasks = new ObservableCollection<Task>(tasks);
                SelectedItem.EffectiveHours = tasks.Sum(t => t.EffectiveHours);
            });            
        }
        
        private ICollection<BacklogItemViewModel> backlogItems;
        public ICollection<BacklogItemViewModel> BacklogItems {
            get {
                return backlogItems;
            }
            set {
                backlogItems = value;
                OnPropertyChanged("BacklogItems");
            }
        }

        public string ImageUrl {
            get { return "pack://application:,,,/ScrumFactory.HelpDeskPlugin;component/Images/help_desk.png"; }
        }

        public int PanelDisplayOrder {
            get { return 50; }
        }

        public string PanelName {
            get { return Properties.Resources.Help_desk; }
        }

        public Composition.ViewModel.DockPanelPlacements PanelPlacement {
            get { return DockPanelPlacements.DockPanelLeft; }
        }

        [Import(typeof(HelpDesk))]
        public Composition.View.IView View {
            get;
            set;
        }

        public ICommand OnLoadCommand { get; set; }
        public ICommand RefreshCommand { get; set; }
        
        public ICommand CloseJobCommand { get; set; }

        public ICommand AddTaskCommand { get; set; }
        public ICommand ConfirmAddTaskCommand { get; set; }
        public ICommand CancelAddTaskCommand { get; set; }

        public ICommand ShowTaskCommand { get; set; }

        public ICommand ShowItemCommand { get; set; }
        
    }
}
